﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using StockShark.Models;

namespace StockShark.BusinessModels
{
    public class InstrumentsSynchroznier
    {
        public StockSharkDB db = new StockSharkDB();
        public StockQuotesParser Parser;

        public InstrumentsSynchroznier() 
        {
            Parser = new StockQuotesParser();
            db.Database.Connection.ConnectionString = "data source=.\\SQLEXPRESS;Integrated Security=SSPI;Initial Catalog=StockSharkDB;";
        }

        /// <summary>
        /// Metoda synchronizująca historię notowań
        /// Notowania synchronizowane jeśli: 1. jest połączenie z bazą, 2. czas to 23.30-23.59, 3. historia nie została
        /// już wcześniej zaktualizowana
        /// </summary>
        /// <returns>Zwraca 1 - poprawnie przeprowadzona synchronizacja, 0 - historia aktualna, więc synchronizacja nie jest
        /// przeprowadzana, -1 - błąd synchronizacji</returns>
        public int Synchronize()
        {
            try
            {
                if (db.Database.Exists())
                {
                    if (IsSynchronizingNeeded() && IsTimeForSynchronizing())
                    {
                        // jeżeli otwarte okno to aktualizowane są również instrumenty
                        if (GameProperties.MarketOpen()) 
                        {
                            SynchronizeInstruments();
                        }

                        // usunięcie orderów
                        SynchronizeOrders();

                        SynchronizeBrokerageAccounts();

                        db.SaveChanges();
                        return 1;
                    }
                    else
                    {
                        return 0;
                    }
                }
                else 
                {
                    return -1;
                }
            }
            catch 
            {
                return -1;
            }
        }

        /// <summary>
        /// Metoda sprawdzająca czy jest odpowiedni czas dla synchronizacji
        /// </summary>
        /// <returns>Zwraca true dla czasu synchronizacji a więc 23.30-23.59</returns>
        public bool IsTimeForSynchronizing()
        {
            if (DateTime.Now.Hour == 23 && DateTime.Now.Minute >= 30 && DateTime.Now.Minute <= 59)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// Metoda sprawdzająca czy potrzebna jest aktualizacja historii, a więc czy do historii zostały
        /// zapisane dane z aktualnego dnia.
        /// </summary>
        /// <returns>czy aktualizacja historii jest wymagana; zwraca true jeśli nie ma aktualnej historii w bazie</returns>
        public bool IsSynchronizingNeeded()
        {
            try
            {
                // dane dla notowania o id 1 ze względu na iż historia tworzona jest dla wszytkich notowań
                // więc id może mieć dowolną wartość
                IEnumerable<Quotation> quotationsForFirstId = from item in db.Quotations
                                                              where item.PaperId == 1
                                                              orderby item.Timestamp, item.Id
                                                              select item;

                // brak historii w bazie więc synchronizajca wymagana
                Quotation actualQuotation = quotationsForFirstId.Last<Quotation>();
                if (actualQuotation.Equals(null))
                {
                    return true;
                }
                else
                {
                    if (actualQuotation.Timestamp.ToString("d") != DateTime.Now.Date.ToString("d"))
                    {
                        return true;
                    }
                    else
                    {
                        return false;
                    }
                }
            }
            catch 
            {
                // błąd spowodowany pustą bazą więc aktualizacja potrzebna
                return true;
            }
        }

        public int SynchronizeInstruments()
        {
            try
            {
                IEnumerable<Instrument> instruments = from instr in db.Instruments
                                                      select instr;

                if (instruments.First<Instrument>() == null)
                {
                    return -1;
                }

                foreach (Instrument item in instruments)
                {
                    item.ReferencePrice = item.CurrentPrice;
                    item.CurrentPrice = 0;
                    db.Quotations.Add(new Quotation { Paper = item, PaperId = item.Id, Timestamp = DateTime.Now.Date, Value = item.ReferencePrice });
                    db.Entry(item).State = System.Data.EntityState.Modified;
                }

                return 1;
            }
            catch 
            {
                return -1;
            }
        }

        public int SynchronizeOrders()
        {
            try
            {
                IEnumerable<Order> orders = from order in db.Orders
                                            select order;

                if (orders.First<Order>() == null)
                {
                    return -1;
                }

                foreach (Order order in orders)
                {
                    if (order.Deadline >= DateTime.Today)
                    {
                        db.Orders.Remove(order);
                    }
                }
                return 1;
            }
            catch 
            {
                return -1;
            }
        }

        public int SynchronizeBrokerageAccounts()
        {
            try
            {
                IEnumerable<BrokerageAccount> bas = from ba in db.BrokerageAccounts
                                                    select ba;

                if (bas.First<BrokerageAccount>() == null)
                {
                    return -1;
                }

                foreach (BrokerageAccount ba in bas)
                {
                    ba.TotalValue = ba.Balance;
                    foreach (OwnedInstrument oi in ba.OwnedInstruments)
                    {
                        ba.TotalValue += oi.TotalValue;
                    }
                    db.AccountValues.Add(new AccountValue() { BrokerageAccount = ba, Timestamp = DateTime.Now.Date, Value = ba.TotalValue });
                }
                return 1;
            }
            catch 
            {
                return -1;
            }
        }
    }
}
